class ChatCacheDB {
  constructor(params) {
    if (!params || typeof params !== 'object') {
      throw new Error('Invalid parameters: must provide configuration object');
    }

    // 验证必要参数
    const requiredParams = ['dbName', 'cacheTableName', 'keyPath'];
    for (const param of requiredParams) {
      if (!params[param]) {
        throw new Error(`Missing required parameter: ${param}`);
      }
    }

    this.dbName = params.dbName;
    this.cacheTableName = params.cacheTableName;
    this.keyPath = params.keyPath;
    this.indexs = params.indexs || [];
    this.db = null;
    this.indexedDB = this._getIndexedDB();
    this._isOpen = false;
  }

  // 私有方法：获取兼容的 indexedDB 实例
  _getIndexedDB() {
    // 1. 浏览器环境
    if (typeof window !== 'undefined' && window.indexedDB) {
      return window.indexedDB;
    }
    // 2. Web Worker 环境
    else if (typeof self !== 'undefined' && self.indexedDB) {
      return self.indexedDB;
    }
    // 3. Node.js 环境（使用 fake-indexeddb）
    else if (typeof require !== 'undefined') {
      try {
        const fakeIndexedDB = require('fake-indexeddb');
        // 同时需要 polyfill 其他相关对象
        if (!global.IDBKeyRange) {
          global.IDBKeyRange = require('fake-indexeddb/lib/FDBKeyRange');
        }
        return fakeIndexedDB;
      } catch (e) {
        console.warn('fake-indexeddb not installed. Run: npm install fake-indexeddb');
        return null;
      }
    }
    // 4. 其他不支持的环境
    return null;
  }

  // 检查是否支持 IndexedDB
  isSupported() {
    return !!this.indexedDB;
  }

  // 检查数据库是否已打开
  isOpen() {
    return this._isOpen && this.db;
  }

  // 打开或创建数据库
  async openDB() {
    if (!this.isSupported()) {
      throw new Error('IndexedDB is not supported in this environment');
    }

    if (this.isOpen()) {
      console.warn('Database is already open');
      return this.db;
    }

    return new Promise((resolve, reject) => {
      const request = this.indexedDB.open(this.dbName, 1);

      request.onerror = (event) => {
        const error = event.target.error;
        console.error('Database opening error:', error);
        reject(new Error(`Failed to open database: ${error.message}`));
      };

      request.onblocked = () => {
        console.warn('Database opening is blocked');
        reject(new Error('Database opening blocked (maybe another connection is open)'));
      };

      request.onsuccess = (event) => {
        this.db = event.target.result;
        this._isOpen = true;
        
        // 监听数据库关闭事件
        this.db.onclose = () => {
          this._isOpen = false;
          console.log('Database connection closed');
        };
        
        // 监听数据库版本变更事件
        this.db.onversionchange = () => {
          console.log('Database version change detected');
          this.db.close();
          this._isOpen = false;
        };
        
        // console.log('Database opened successfully');
        resolve(this.db);
      };

      request.onupgradeneeded = (event) => {
        const db = event.target.result;
        if (!db.objectStoreNames.contains(this.cacheTableName)) {
          try {
            const objectStore = db.createObjectStore(this.cacheTableName, {
              keyPath: this.keyPath,
              autoIncrement: false
            });
            
            this.indexs.forEach((index) => {
              if (index.name && typeof index.name === 'string') {
                objectStore.createIndex(index.name, index.name, {
                  unique: !!index.unique
                });
              }
            });
            console.log('Object store and indexes created successfully');
          } catch (e) {
            console.error('Error creating object store:', e);
            event.target.transaction.abort();
            reject(e);
          }
        }
      };
    });
  }

  // 添加或更新数据
  async putData(data) {
    if (!this.isOpen()) {
      await this.openDB(); // 打开数据库
      // throw new Error('Database is not open');
    }

    if (!data || typeof data !== 'object') {
      throw new Error('Invalid data: must be an object');
    }

    if (!data[this.keyPath]) {
      throw new Error(`Data must contain the keyPath property: ${this.keyPath}`);
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.cacheTableName], 'readwrite');
      const objectStore = transaction.objectStore(this.cacheTableName);
      const request = objectStore.put(data);

      request.onerror = (event) => {
        const error = event.target.error;
        console.error('Data put error:', error);
        reject(new Error(`Failed to put data: ${error.message}`));
      };

      transaction.oncomplete = () => {
        resolve(data[this.keyPath]); // 返回主键值
      };

      transaction.onerror = (event) => {
        const error = event.target.error;
        console.error('Transaction error:', error);
        reject(new Error(`Transaction failed: ${error.message}`));
      };
    });
  }

  // 批量添加数据
  async putAllData(items) {
    if (!Array.isArray(items)) {
      throw new Error('Items must be an array');
    }

    const results = [];
    for (const item of items) {
      try {
        const result = await this.putData(item);
        results.push(result);
      } catch (e) {
        console.error(`Failed to put item with key ${item[this.keyPath]}:`, e);
        throw e; // 可以选择继续或终止
      }
    }
    return results;
  }

  // 根据主键获取数据
  async getData(key) {
    
    if (!this.isOpen()) {
      // throw new Error('Database is not open');
      await this.openDB();
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.cacheTableName], 'readonly');
      const objectStore = transaction.objectStore(this.cacheTableName);
      const request = objectStore.get(key);

      request.onerror = (event) => {
        const error = event.target.error;
        console.error('Data get error:', error);
        reject(new Error(`Failed to get data: ${error.message}`));
      };

      request.onsuccess = (event) => {
        resolve(event.target.result || null);
      };
    });
  }

  // 根据索引获取数据
  async getDataByIndex(indexName, value) {
    if (!this.isOpen()) {
       await this.openDB();
      // throw new Error('Database is not open');
    }

    if (!indexName || typeof indexName !== 'string') {
      throw new Error('Invalid index name');
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.cacheTableName], 'readonly');
      const objectStore = transaction.objectStore(this.cacheTableName);
      
      if (!objectStore.indexNames.contains(indexName)) {
        reject(new Error(`Index ${indexName} does not exist`));
        return;
      }

      const index = objectStore.index(indexName);
      const request = index.get(value);

      request.onerror = (event) => {
        const error = event.target.error;
        console.error('Data get by index error:', error);
        reject(new Error(`Failed to get data by index: ${error.message}`));
      };

      request.onsuccess = (event) => {
        resolve(event.target.result || null);
      };
    });
  }

  // 获取所有数据
  async getAllData() {
    if (!this.isOpen()) {
      throw new Error('Database is not open');
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.cacheTableName], 'readonly');
      const objectStore = transaction.objectStore(this.cacheTableName);
      const request = objectStore.getAll();

      request.onerror = (event) => {
        const error = event.target.error;
        console.error('Get all data error:', error);
        reject(new Error(`Failed to get all data: ${error.message}`));
      };

      request.onsuccess = (event) => {
        resolve(event.target.result || []);
      };
    });
  }

  // 根据索引获取所有匹配数据
  async getAllDataByIndex(indexName, value) {
    if (!this.isOpen()) {
      throw new Error('Database is not open');
    }

    if (!indexName || typeof indexName !== 'string') {
      throw new Error('Invalid index name');
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.cacheTableName], 'readonly');
      const objectStore = transaction.objectStore(this.cacheTableName);
      
      if (!objectStore.indexNames.contains(indexName)) {
        reject(new Error(`Index ${indexName} does not exist`));
        return;
      }

      const index = objectStore.index(indexName);
      const request = index.getAll(value);

      request.onerror = (event) => {
        const error = event.target.error;
        console.error('Get all data by index error:', error);
        reject(new Error(`Failed to get all data by index: ${error.message}`));
      };

      request.onsuccess = (event) => {
        resolve(event.target.result || []);
      };
    });
  }

  // 删除数据
  async deleteData(key) {
    if (!this.isOpen()) {
      throw new Error('Database is not open');
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.cacheTableName], 'readwrite');
      const objectStore = transaction.objectStore(this.cacheTableName);
      const request = objectStore.delete(key);

      request.onerror = (event) => {
        const error = event.target.error;
        console.error('Data delete error:', error);
        reject(new Error(`Failed to delete data: ${error.message}`));
      };

      transaction.oncomplete = () => {
        resolve(true);
      };

      transaction.onerror = (event) => {
        const error = event.target.error;
        console.error('Transaction error:', error);
        reject(new Error(`Transaction failed: ${error.message}`));
      };
    });
  }

  // 清空对象存储
  async clearStore() {
    if (!this.isOpen()) {
      throw new Error('Database is not open');
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.cacheTableName], 'readwrite');
      const objectStore = transaction.objectStore(this.cacheTableName);
      const request = objectStore.clear();

      request.onerror = (event) => {
        const error = event.target.error;
        console.error('Clear store error:', error);
        reject(new Error(`Failed to clear store: ${error.message}`));
      };

      transaction.oncomplete = () => {
        resolve(true);
      };

      transaction.onerror = (event) => {
        const error = event.target.error;
        console.error('Transaction error:', error);
        reject(new Error(`Transaction failed: ${error.message}`));
      };
    });
  }

  // 关闭数据库
  closeDB() {
    if (this.isOpen()) {
      this.db.close();
      this._isOpen = false;
      console.log('Database closed');
    }
  }
  // 更新字段数据
   /**
   * 更新数据中的特定字段
   * @param {string|number} key - 要更新的数据主键
   * @param {object} updates - 包含要更新的字段和值的对象
   * @returns {Promise<boolean>} - 更新是否成功
   */
  async updateData(key, updates) {
    if (!this.isOpen()) {
      await this.openDB();
    }

    if (!key) {
      throw new Error('Invalid key: must provide a valid key');
    }

    if (!updates || typeof updates !== 'object' || Object.keys(updates).length === 0) {
      throw new Error('Invalid updates: must provide a non-empty object with updates');
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.cacheTableName], 'readwrite');
      const objectStore = transaction.objectStore(this.cacheTableName);
      
      // 1. 首先获取现有数据
      const getRequest = objectStore.get(key);

      getRequest.onerror = (event) => {
        const error = event.target.error;
        console.error('Data get error during update:', error);
        reject(new Error(`Failed to get data for update: ${error.message}`));
      };

      getRequest.onsuccess = (event) => {
        const existingData = event.target.result;
        
        if (!existingData) {
          reject(new Error(`No data found with key: ${key}`));
          return;
        }

        // 2. 合并更新到现有数据
        const updatedData = {
          ...existingData,
          ...updates
        };

        // 3. 保存更新后的数据
        const putRequest = objectStore.put(updatedData);

        putRequest.onerror = (event) => {
          const error = event.target.error;
          console.error('Data update error:', error);
          reject(new Error(`Failed to update data: ${error.message}`));
        };

        putRequest.onsuccess = () => {
          resolve(true);
        };
      };

      transaction.onerror = (event) => {
        const error = event.target.error;
        console.error('Transaction error during update:', error);
        reject(new Error(`Transaction failed during update: ${error.message}`));
      };
    });
  }


  // 删除数据库
  async deleteDB() {
    this.closeDB(); // 先关闭现有连接

    return new Promise((resolve, reject) => {
      if (!this.isSupported()) {
        reject(new Error('IndexedDB is not supported in this environment'));
        return;
      }

      const request = this.indexedDB.deleteDatabase(this.dbName);

      request.onerror = (event) => {
        const error = event.target.error;
        console.error('Database deletion error:', error);
        reject(new Error(`Failed to delete database: ${error.message}`));
      };

      request.onsuccess = () => {
        console.log('Database deleted successfully');
        resolve(true);
      };

      request.onblocked = () => {
        console.warn('Database deletion blocked (database is in use)');
        reject(new Error('Database deletion blocked (database is in use)'));
      };
    });
  }
}





// 示例配置
const dbConfig = {
  dbName: 'ChatAppDB',
  cacheTableName: 'messages',
  keyPath: 'id',
  indexs: [
    { name: 'roomId', unique: false },
    { name: 'timestamp', unique: false },
    { name: 'userId', unique: false }
  ]
};

// 使用示例
async function demo() {
  try {
    // 1. 创建实例
    const chatDB = new ChatCacheDB(dbConfig);
    
    // 2. 检查支持性
    if (!chatDB.isSupported()) {
      console.error('IndexedDB is not supported in this environment');
      return;
    }
    
    // 3. 打开数据库,实际是初始化/打开
    await chatDB.openDB();
    
    console.log('Database ready');
    
    // 4. 添加数据
    const message1 = {
      id: 'msg_001',
      roomId: 'room_123',
      userId: 'user_456',
      text: 'Hello world!', 
      timestamp: Date.now()
    };
    
    await chatDB.putData(message1);
    console.log('Message saved');
    
    // 5. 批量添加
    const messages = [
      { id: 'msg_002', roomId: 'room_123', userId: 'user_789', text: 'Hi there!', timestamp: Date.now() },
      { id: 'msg_003', roomId: 'room_456', userId: 'user_456', text: 'How are you?', timestamp: Date.now() }
    ];
    
    await chatDB.putAllData(messages);
    console.log('Batch save complete');
    
    // 6. 查询数据
    const msg = await chatDB.getData('msg_001');
    console.log('Retrieved message:', msg);
    
    // 7. 按索引查询
    const roomMessages = await chatDB.getAllDataByIndex('roomId', 'room_123');
    console.log('Room messages:', roomMessages);
    
    // 8. 获取所有数据
    const allMessages = await chatDB.getAllData();
    console.log('All messages:', allMessages.length);
    
    // 9. 删除数据
    await chatDB.deleteData('msg_002');
    console.log('Message deleted');
    
    // 10. 清空存储
    // await chatDB.clearStore();
    
  } catch (error) {
    console.error('Error:', error);
  }
}

// 运行示例
// demo();

// 导出类
export default ChatCacheDB;